﻿using System;
using System.Collections.Generic;
using System.Text;
using AdaptiveAgents.Experiments;
using AdaptiveAgents.Agents;
using AdaptiveAgents.Distributions;
using AdaptiveAgents.Games;
using AdaptiveAgents.Loggers;
using AdaptiveAgents.Running_Tools.Runnings_Packages;
using AdaptiveAgents.Running_Tools.Agent_Lists;

namespace AdaptiveAgents.Running_Tools
{
    /// <summary>
    /// This class build all the experiment part
    /// </summary>
    class Strategist
    {
        /// <summary>
        /// Create Experiment By "InputEntry" data.
        /// </summary>
        /// <param name="input">input data</param>
        /// <returns>Complete Experiment unit</returns>
        public static Experiment createExperiment(InputPackage input)
        {
            Experiment returnEx = null;
            string exp = input.ExperimentType;
            ExperimentEntry expData = new ExperimentEntry(input);

            // create Experiment by exp String
            if (exp.Equals("NormalNAgentExperiment"))
            {
                returnEx = new NormalNAgentExperiment(expData);
                returnEx.Logger = input.Logger;
            }
             
            return returnEx;
        }


        /// <summary>
        /// This function create "AgentDataList" from the input data
        /// </summary>
        /// <param name="AgentsTypeList">"String" list of agents type</param>
        /// <param name="isRandom">Sign if we get agents data random or from file</param>
        /// <param name="FilePath">File path of agents data file</param>
        /// <returns>AgentsTypeList of "Input data" for agents</returns>
        public static List<AgentInput> createAgentDataList(List<string> AgentsList, Boolean isRandom, string FilePath)
        {
            List<AgentInput> list = null;

            // create random list
            if (isRandom)
            {
                list = AgentsDataListCreator.createRandomList(AgentsList);
            }// create agent data list from file
            else
            {
                list = AgentsDataListCreator.createListFromFile(AgentsList,FilePath);
            }

            return list;
        }


        /// <summary>
        /// Create Title for "DataTable" unit
        /// </summary>
        /// <param name="gameType">Game Type</param>
        /// <returns>The title</returns>
        public static string craeteDataBaseTitle(string gameType)
        {
            string start = gameType;
            string end = "-";

            return start + end;
        }


        /// <summary>
        /// The function create AgentsTypeList of Agents
        /// </summary>
        /// <param name="env">"Envirinment" unit</param>
        /// <param name="agentDataList">AgentsTypeList of agent data input list</param>
        /// <param name="epsilonsList">AgentsTypeList of epsilons for the agents</param>
        /// <param name="competenceList">AgentsTypeList of competence for the agents</param>
        /// <param name="logger">"Logger" unit</param>
        /// <returns>Agent list</returns>
        public static List<Agent> createAgentsList(Environment env, List<AgentInput> agentDataList, List<double> epsilonsList, List<double> competenceList, Logger logger)
        {
            //create agents list
            List<Agent> returnList = new List<Agent>();
            //create director
            AgentDirector director = new AgentDirector();
            director.Builder = chooseAgentBuilder(agentDataList[0].AgentType,epsilonsList,competenceList);


            Agent ag;
            //construct the first agent
            director.construct(0, env, 0, logger);
            ag = director.getAgent();
            ag.ChangeStrategyPoint = 100;
            returnList.Add(ag);
            

            //construct the 2nd and Nth agents 
            for (int i = 1; i < agentDataList.Count; i++)
            {
                director.Builder = chooseAgentBuilder(agentDataList[i].AgentType, epsilonsList, competenceList);
                director.construct(i, env, epsilonsList[i], logger);
                returnList.Add(director.getAgent());
              
            }

            return returnList;
        }
        

        /// <summary>
        /// This function choose the agent builder 
        /// </summary>
        /// <param name="agentType">String of agent type</param>
        /// <param name="epsilonsList">AgentsTypeList of epsilons</param>
        /// <param name="competenceList">AgentsTypeList of competence</param>
        /// <returns>"Agent Builder" unit</returns>
        private static AgentBuilder chooseAgentBuilder(string agentType, List<double> epsilonsList, List<double> competenceList)
        {
            AgentBuilder builder = null;
            string AGENT_TYPE = agentType.ToUpper();

            if (AGENT_TYPE.Equals("GREEDY"))
            {
                builder = new GreedyBuilder();
            }
            else if (AGENT_TYPE.Equals("MDP_DISCOVER"))
            {
                builder = new MDPDiscoverBuilder();
            }
            else if (AGENT_TYPE.Equals("MDP_OPTIMAL"))
            {
                builder = new MDPOptimalBuilder(competenceList, epsilonsList);
            }
            else if (AGENT_TYPE.Equals("NORMAL"))
            {
                builder = new NormalBuilder();
            }
            
            return builder;
        }


        /// <summary>
        /// This Function create "Game" unit
        /// </summary>
        /// <param name="GameType">Game type</param>
        /// <param name="env">"Environment" unit</param>
        /// <param name="numOfRounds">Number of rounds</param>
        /// <returns>"Game" unit</returns>
        public static Game createGame(string GameType, Environment env, int numOfRounds)
        {
            Game retGame = null;

            if (GameType.Equals("NormalGame"))
            {
                    retGame = new NormalGame(env, numOfRounds);
            }
            else if (GameType.Equals("CyclicGame"))
            {
                    retGame = new CyclicGame(env, numOfRounds);
            }
            else if (GameType.Equals("RectangleTestGame"))
            {
                    retGame = new RectangleTestGame(env, numOfRounds);
            }
            else if (GameType.Equals("EpsilonTestGame"))
            {
                    retGame = new EpsilonTestGame(env, numOfRounds);
            }
            else if (GameType.Equals("OldMDPGame"))
            {
                    retGame = new MDPGame_old(env, numOfRounds);
            }
            else if (GameType.Equals("MDPNoRaiseGame"))
            {
                    retGame = new MDPGameNoRaise(env, numOfRounds);
            }
            else if (GameType.Equals("MDPNoRaiseCompetenceGame"))
            {
                    retGame = new MDPNoRaiseCompetenceGame(env, numOfRounds);
            }
            else if (GameType.Equals("MDPFindDifferentGame"))
            {
                    retGame = new MDPFindDifferentGame(env, numOfRounds);
            }
            else if (GameType.Equals("NormalGameToCSV"))
            {
                    retGame = new NormalGameToCSV(env, numOfRounds);
            }
            else if (GameType.Equals("NewMDPGame"))
            {
                    retGame = new MDPGame(env, numOfRounds, true);
            }
            else if (GameType.Equals("MDPWithoutUpdateCompetanceGame"))
            {
                retGame = new MDPGame(env, numOfRounds, false);
            }

          

            return retGame;
        }


        /// <summary>
        /// This function create agets type list.
        /// </summary>
        /// <param name="agentListType">The type of the list</param>
        /// <param name="size">The size of the list</param>
        /// <returns>Complete AgentsTypeList</returns>
        public static AgentsTypeList createAgentsTypeList(string agentListType, int size)
        {
            AgentsTypeList returnList = null;
           
            if (agentListType.Equals("GreedyAgentList"))
            {
                returnList = new GreedyAgentsList(size);
            }
            else if (agentListType.Equals("MDPDiscoverAgentList"))
            {
                returnList = new MDPDiscoverAgentsList(size);
            }
            else if (agentListType.Equals("MDPOptimalAgentList"))
            {
                returnList = new MDPOptimalAgentsList(size);
            }
            else if (agentListType.Equals("NormalAgentList"))
            {
                returnList = new NormalAgentsList(size);
            }
            else if (agentListType.Equals("NormalAgentListWithGreedyAdaptiveAgent"))
            {
                returnList = new NormalAgentsListWithAdaptiveGreedyAgent(size);
            }
            else if (agentListType.Equals("NormalAgentListWithMDPDiscoverAdaptiveAgent"))
            {
                returnList = new NormalAgentsListWithAdaptiveMDPDiscoverAgent(size);
            }
            else if (agentListType.Equals("NormalAgentListWithMDPOptimalAdaptiveAgent"))
            {
                returnList = new NormalAgentsListWithAdaptiveMDPOptimalAgent(size);
            }
            
            return returnList;
        }

    }
}
